import { validateUserPwdRule } from 'utils/modules/validateUserPwdRule';
// @ts-ignore jsencrypt没有相关的ts包
import JSEncrypt from 'jsencrypt';
import moment from 'moment';
import qs from 'query-string';
import { notification } from 'antd';
import { getSysUserInfo, queryWebSensitiveSwitch } from 'admin/servers/servers';
import store from 'store';
import { SM4Util } from 'utils/sm4/sm4.js';

const sm4 = new SM4Util();

/**
 * 保留N位小数
 * 最终返回的是字符串
 * 若转换失败，返回参数原值
 * @param str - 数字或字符串
 * @param x   - 保留几位小数点
 */
export const pointX = (str: string | number, x = 0): string | number => {
  if (!str && str !== 0) {
    return str;
  }
  const temp = Number(str);
  if (temp === 0) {
    return temp.toFixed(x);
  }
  return temp ? temp.toFixed(x) : str;
};

/**去掉字符串两端空格*/
export const trim = (str: string): string => {
  const reg = /^\s*|\s*$/g;
  return str.replace(reg, '');
};

/**
  给字符串打马赛克
  如：将123456转换为1****6，最多将字符串中间6个字符变成*
  如果字符串长度小于等于2，将不会有效果
*/
export const addMosaic = (str: string): string => {
  const s = String(str);
  const lenth = s.length;
  const howmuch = ((): number => {
    if (lenth <= 2) {
      return 0;
    }
    const l = lenth - 2;
    if (l <= 6) {
      return l;
    }
    return 6;
  })();
  const start = Math.floor((lenth - howmuch) / 2);
  const ret = s.split('').map((v, i) => {
    if (i >= start && i < start + howmuch) {
      return '*';
    }
    return v;
  });
  return ret.join('');
};
/**手机号脱敏加密,共11位，前三后四显示，例如：181****6988 */
export const phoneMask = (str: string): string => str.replace(/(\d{3})\d*(\d{4})/, '$1****$2');

/**身份证号脱敏加密,共18位，第一位和最后一位显示，例如：4****************X */
export const idCardMask = (str: string): string =>
  str.replace(/(\d{1})\d*(\d{1})/, '$1****************$2');

/**转为百分比，n为小数点位数 */
export const toPercent = (num: number, total = 100, n = 1): string => {
  // per：百分比值（包含小数点2位，如85.21）
  const per = Math.round((num / total) * 10000) / 100;
  return per > 0 ? (per === 100 ? '100%' : per.toFixed(n) + '%') : '0%';
};

/**
 * 正则：验证字符串
 * 只能为字母、数字、下划线
 * 可以为空
 * **/
export const checkStr = (str: string): boolean => {
  if (str === '') {
    return true;
  }
  const rex = /^[_a-zA-Z0-9]+$/;
  return rex.test(str);
};

/**
 * 正则：验证数字字符串(非空)，例如：'10001'
 * **/
export const checkNumber = (str: string): boolean => {
  if (!str) {
    return false;
  }
  const rex = /^\d*$/;
  return rex.test(str);
};

/** 正则：手机号验证 **/
export const checkPhone = (str: string | number): boolean => {
  const rex = /^1[34578]\d{9}$/;
  return rex.test(String(str));
};

/** 正则：邮箱验证 **/
export const checkEmail = (str: string): boolean => {
  const rex = /^[a-zA-Z0-9]+([-_.][a-zA-Z0-9]+)*@[a-zA-Z0-9]+([-_.][a-zA-Z0-9]+)*\.[a-z]{2,}$/;
  return rex.test(str);
};
/**
  字符串加密
  简单的加密方法
*/
export const compile = (code: string): string => {
  let c = String.fromCharCode(code.charCodeAt(0) + code.length);
  for (let i = 1; i < code.length; i++) {
    c += String.fromCharCode(code.charCodeAt(i) + code.charCodeAt(i - 1));
  }
  return c;
};

/**
  字符串解谜
  对应上面的字符串加密方法
*/
export const uncompile = (code: string): string => {
  let c = String.fromCharCode(code.charCodeAt(0) - code.length);
  for (let i = 1; i < code.length; i++) {
    c += String.fromCharCode(code.charCodeAt(i) - c.charCodeAt(i - 1));
  }
  return c;
};

/**
 * 清除一个对象中属性字段对应的值为null和undefined
 * 主要用于发送请求，去掉无意义字段
 * 0 false 算有效值
 * **/
export function clearNull<T>(obj: T): T {
  const temp = { ...obj } as any;
  Object.keys(temp).forEach(key => {
    if (temp[key] === null || temp[key] === undefined) {
      delete temp[key];
    }
  });
  return temp;
}

/**
 * 加密字符
 */
export const encryptStr = (str: string, useRSA = false): string => {
  if (useRSA) {
    const encryptObj = new JSEncrypt();
    const RSAPublic =
      'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmLplG5iNsCCHOQsUB5dfdTL++R7dIp6xS8xVg2e9KfFtfbCTeAs7U3vb1uGdX5RLDO07ADyvKDhSPYSuoXRPkw9IIe16/EoSPSmPpGketiBgaH92nleQQTPe+9uSO399HoVlnhqaJGzz88zWsYR6tpncYtqNIjV2vrTo8Iy0kQwIDAQAB';
    encryptObj.setPublicKey(RSAPublic);
    return encryptObj.encrypt(str);
  }

  // 替换国产SM4加密
  return sm4.encryptData_CBC(str);
};

/**
 * 解密字符
 */
export const decryptStr = (str: string): string => {
  // const encryptObj = new JSEncrypt();
  // const RSAPrivate =
  //   'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKQicH/ULX65zRJHunplhPIaNA5aKqpSYXdfDbtep/uCDJHLYAc57rl2OQgry5Yy9roHNnthx2yj6gLrPUuN4+BBMKjPeOc1CHBFZed6WFUY0vpK3O32NHrCgjtSIiOsH+GED0CBUT7f9ddeTQVzyKVepG0Nn89a2uMiCM655IojAgMBAAECgYBsBGY5Ge/e6HQ3RZFJn6oAkpITp+9QK+sM3jdxSfgPIyUWhdtqpgufblhWMkxHSr7o6npGdLEDpFQLG7k5EeYWzoYVLj/3ziB4ShRVIqeqKXO8CUfFpE3oZNFVG7Kzm86hsyeX3guBNvjiadoF0zLB0JHovh5cy1+Hr2FN/iTegQJBAOGOWdeaFbh7JVpv9OQTfekOxva5ilfZIoi3JZGv+L3LX2OMp1AbjgCKN51AnMxYwPmCdvRAZGBTFKfDfrv+VcMCQQC6ScmbQdi6MmSswKataav1E4zFcuuBp7selh3ahBjfPZOIAakT8HmZHoZkoSTBjM3bGOhjSZTfjrWREbl1MtQhAkAnjhQ5WB85A/eP/ZQ/rx9kkJ/Zwr39G+oPebbP7sE7X3/x8EejJ8HmXFbWb+9Pcr0cxIFh4iz4K3my1fjStQ6LAkEAtGjza33Yk3JsV3V3tifJld4qDaqe84DqUdPV86LMp55tu2DISvwv9x89zkTVYPCpCE/V9xnyqJL/ug+tSRhBoQJBAL1SoWF+5XvPniRHA0dsatJhiIAHzzYXE2gqD2RJmP1/conMCdh7Wa5zkk4hftdtpkJlM6SQdP60nITH3nOcBvE=';
  // encryptObj.setPrivateKey(RSAPrivate);
  // return encryptObj.decrypt(str);

  // 替换国产SM4解密
  return sm4.decryptData_CBC(str);
};
/**
 * 计算table序号
 */
export const getTableIndex = (index: number, pageSize: number, current: number): number => {
  return index + 1 + pageSize * (current - 1);
};

/**
 * 根据分钟数计算时间
 * exam：入参90，返回1小时30分
 */
export const getTimeByMin = (min: number): string => {
  const minStr = parseInt((min % 60) as any);
  const hourStr = parseInt((min / 60) as any);
  if (hourStr === 0) {
    return `${minStr}分钟`;
  } else {
    return `${hourStr}小时${minStr}分钟`;
  }
};

/**@description JS生成的随机数中，排除数字0开头,位数为n */
export function randomNum(n = 3) {
  let num = '';
  for (let i = 0; i < n; i++) {
    if (i === 0) {
      num += Math.floor(Math.random() * 9 + 1);
    } else {
      num += Math.floor(Math.random() * 10);
    }
  }
  console.log(num);
  return num;
}

/**通话记录：根据index去重 */
export function filterDialogue(arr: any[]) {
  const res = new Map();
  return arr.filter(a => !res.has(a.index) && res.set(a.index, 1));
}
/**
 *删除列表数据成功后，刷新当前页数据
 * @param size 删除条数
 * @param pageTotal 总数
 * @param pageNum 当前页码
 * @param pageSize 当前页展示数据条数
 * @returns 最新页码
 */
export const deleteRowChangePageNum = (
  size: number,
  pageTotal: number,
  pageNum: number,
  pageSize: number
) => {
  // 此时已经实现删除操作，所以total的值需要减size，Math.ceil是向上取整，保证始终大于等于0
  const totalPage = Math.ceil((pageTotal - size) / pageSize);
  //将当前页码与删除数据之后的总页数进行比较，避免当前页码不存在
  const pagenum = pageNum > totalPage ? totalPage : pageNum;

  //避免pagenum变为0，默认返回第一页
  pageNum = pagenum < 1 ? 1 : pagenum;
  return pageNum;
};

/**工作台调试功能开关
 * 部署参数传值则开启调试模式
 * webDebug为true，可在地址栏输入debug=true参数，打开调试信息展示
 */
export const webDebug =
  process.env.REACT_APP_DEBUG?.toString() === '1' ? qs.parse(location.search).debug : false;
/**
 * 毫秒转换成【分:秒】
 * 例如：00:00，
 * 超过1小时如：90:10
 */
export function formatSecond(time: number): string {
  if (!time) {
    return '00:00';
  }
  // 不足两位，补0
  const tf = function (i: number) {
    return (i < 10 ? '0' : '') + i;
  };
  // 分钟数-向下取整
  const minutes = tf(Math.floor(time / 60));
  // 秒钟数-向上取整
  const seconds = tf(Math.ceil(time % 60));
  return `${minutes}:${seconds}`;
}

/**
 * Table数据转换
 * 后端格式：
 * tableTitle【name，key】
 * tableContent【key,value】
 * 场景：动态列，后端对应格式，转换为表格数据展示
 */
export function transformTableData(feedBack: any) {
  // 表格头部列
  const tit: any[] = [];
  // 表格数据
  const list: any[] = [];
  feedBack.tableTitle.forEach((item: any) => {
    // 属性为空的数据列，需剔除
    if (item.key) {
      tit.push({
        title: item.name,
        dataIndex: item.key,
        key: item.key,
      });
    }
  });
  console.log('tit***', tit);
  feedBack.tableContent.forEach((arrItem: any) => {
    console.log(arrItem, '每个数组对象，每行');
    let obj: any = {};
    arrItem.forEach((item: any) => {
      // 属性为空的数据列，需剔除
      if (item.key) {
        console.log(item, '每个对象，字段-键值');
        obj = {
          ...obj,
          [item.key]: item.value,
        };
      }
    });

    // console.log(obj, 456);
    list.push(obj);
  });
  // console.log(list, 789);
  console.log('list***', list);
  return [tit, list];
}

/**
 * 身份证15位编码规则：dddddd yymmdd xx p dddddd：6位地区编码 yymmdd: 出生年(两位年)月日，如：910215 xx:
 * 顺序编码，系统产生，无法确定 p: 性别，奇数为男，偶数为女
 *
 * 身份证18位编码规则：dddddd yyyymmdd xxx y dddddd：6位地区编码 yyyymmdd:
 * 出生年(四位年)月日，如：19910215 xxx：顺序编码，系统产生，无法确定，奇数为男，偶数为女 y: 校验码，该位数值可通过前17位计算获得
 *
 * 前17位号码加权因子为 Wi = [ 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 ] 验证位
 * Y = [ 1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2 ] 如果验证码恰好是10，为了保证身份证是十八位，那么第十八位将用X来代替
 * 校验位计算公式：Y_P = mod( ∑(Ai×Wi),11 ) i为身份证号码1...17 位; Y_P为校验码Y所在校验码数组位置
 */
export function checkIdCard(idCard: any) {
  // 15位和18位身份证号码的正则表达式
  const regIdCard =
    /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/;

  // 如果通过该验证，说明身份证格式正确，但准确性还需计算
  if (regIdCard.test(idCard)) {
    if (idCard.length === 18) {
      const idCardWi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; // 将前17位加权因子保存在数组里
      const idCardY = [1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2]; // 这是除以11后，可能产生的11位余数、验证码，也保存成数组
      let idCardWiSum = 0; // 用来保存前17位各自乖以加权因子后的总和
      for (let i = 0; i < 17; i++) {
        idCardWiSum += idCard?.substring(i, i + 1) * idCardWi[i];
      }

      const idCardMod = idCardWiSum % 11; // 计算出校验码所在数组的位置
      const idCardLast = idCard.substring(17); // 得到最后一位身份证号码

      // 如果等于2，则说明校验码是10，身份证号码最后一位应该是X
      if (idCardMod === 2) {
        if (idCardLast === 'X' || idCardLast === 'x') {
          // alert('恭喜通过验证啦===1！');
          return true;
        } else {
          // alert('身份证号码错误==1！');
          return false;
        }
      } else {
        // 用计算出的验证码与最后一位身份证号码匹配，如果一致，说明通过，否则是无效的身份证号码
        if (parseInt(idCardLast) === idCardY[idCardMod]) {
          // alert('恭喜通过验证啦==2！');
          return true;
        } else {
          // alert('身份证号码错误==2！');
          return false;
        }
      }
    } else {
      return true;
    }
  } else {
    //alert("身份证格式不正确==3!");
    return false;
  }
}

/**检测账号和密码是否过期
 * 账号是30天，开始提醒
 * 密码是15天，开始提醒
 */
export const checkValidate = async () => {
  try {
    const {
      data: { userValidityDate, passwordValidityDate },
    } = await getSysUserInfo();
    const nowTime = new Date();
    // 测试用，上线注释掉
    // const userValidityDate = '2021-12-17';
    // const passwordValidityDate = '2021-12-17';

    /**检测密码是否快过期*/
    const checkPwdExp = () => {
      if (passwordValidityDate) {
        // 密码距离过期天数
        const passwordDays = moment(passwordValidityDate).diff(moment(nowTime), 'days') + 1;
        console.log('==============密码过期相差天数', passwordDays, passwordValidityDate);
        if (passwordDays <= 15) {
          notification.warning({
            className: 'validate-modal',
            message: '请注意!',
            description: `密码将在${passwordDays}天后过期，请及时修改密码。`,
            duration: 0,
          });
        }
      }
    };
    /**检测账号是否快过期 */
    if (userValidityDate) {
      // 账号距离过期天数
      const accountDays = moment(userValidityDate).diff(moment(nowTime), 'days') + 1;
      console.log('==============账号过期相差天数', accountDays, userValidityDate);
      if (accountDays <= 30) {
        notification.warning({
          className: 'validate-modal',
          message: '请注意!',
          description: `账号使用权限将在${accountDays}天后过期，请及时联系管理员进行续期。`,
          duration: 0,
          onClose: checkPwdExp,
        });
      } else {
        checkPwdExp();
      }
    }
  } catch (error) {
    console.error(`系统异常: ${JSON.stringify(error)}`);
  }
};

/**检查页面敏感信息是否显示
 * 默认undefined，不展示
 * false-敏感信息不展示
 * true-敏感信息展示
 */
export const showWebSenstive = async () => {
  let rt = undefined;
  try {
    const res = await queryWebSensitiveSwitch();
    // 设置默认为'on'，信息不展示
    rt = res.data.switchFlag === 'on' ? false : true;
  } catch (error) {
    console.error(`系统异常: ${JSON.stringify(error)}`);
  }
  return rt;
};

/**根据页面敏感配置，生成新数据，变更展示：手机号和身份证号码*/
export const webSenstiveMask = (obj: any, showWebSenstive?: boolean) => {
  const newObj = JSON.parse(JSON.stringify(obj));
  if (newObj.mobile) {
    const text = newObj.mobile;
    newObj.mobile = showWebSenstive ? text : phoneMask(text);
  }
  if (newObj.idCardNumber) {
    const text = decryptStr(newObj.idCardNumber);
    newObj.idCardNumber = showWebSenstive ? text : idCardMask(text);
  }
  return newObj;
};

/**验证非空 */
export const verifyNull = (message?: string) => {
  return [{ required: true, message: message }];
};

/**验证【登录用户】及密码规则*/
export const verifyAccountPwd = [
  { required: true },
  { min: 8, message: '密码位数低于8位' },
  { max: 30, message: '密码位数不高于30位' },
  {
    validator: (_: any, value: string) => {
      const { userName } = store.getState().userInfo;
      console.log('校验登录用户名=====', userName);
      const Fn = validateUserPwdRule;
      const { code, tip, msg } = Fn.checkPassword(userName, value);
      console.log('********密码校验信息：', tip);
      return code ? Promise.reject(msg) : Promise.resolve();
    },
  },
];

/**校验【非登录用户】密码强度规则 */
export const verifyUserPwd = (userName?: string) => [
  { required: true },
  { min: 8, message: '密码位数低于8位' },
  { max: 30, message: '密码位数不高于30位' },
  {
    validator: (_: any, value: string) => {
      console.log('校验非登录用户=====', userName);
      const Fn = validateUserPwdRule;
      const { code, tip, msg } = Fn.checkPassword(userName, value);
      console.log('********密码校验信息：', tip);
      return code ? Promise.reject(msg) : Promise.resolve();
    },
  },
];

/**验证坐席工号（6位，数字） */
export const verifySeatsNumber = [
  { required: true },
  { min: 6, message: '请输入6位数字' },
  { max: 6, message: '请输入6位数字' },
];

/**验证手机或者座机号码（7-11位，数字），例如：黑名单*/
export const verifyTelephone = [
  { required: true, message: '请输入7-11位数字' },
  { min: 7, message: '请输入7-11位数字' },
  { max: 11, message: '请输入7-11位数字' },
];

/**验证转人工组件指定号码（1-30位号码），此处是特例*/
export const verifyTansferNumber = [
  { required: true, message: '请输入1-30位号码' },
  { min: 1, message: '请输入1-30位号码' },
  { max: 30, message: '请输入1-30位号码' },
];

/**验证账号 */
export const verifyAccount = [
  { required: true },
  {
    validator: (_: any, value: string) => {
      return checkStr(value) ? Promise.resolve() : Promise.reject('请输入英文数字下划线');
    },
  },
];

/**验证手机号(13位，如：13912345678) */
export const verifyPhone = [
  {
    required: true,
  },
  {
    validator: (_: any, value: number) => {
      return /^1[3|4|5|6|7|8|9][0-9]\d{8}$/.test(value.toString())
        ? Promise.resolve()
        : Promise.reject('请输入正确格式的手机号');
    },
  },
];

/**验证身份证(18位) */
export const verifyIdCard = [
  {
    required: true,
  },
  {
    validator: (_: any, value: number) => {
      return checkIdCard(value.toString())
        ? Promise.resolve()
        : Promise.reject('身份证号码格式不正确');
    },
  },
];
